import { UeESVisualObject, UeViewer, ESSeparateFoliage, getFlyToCenterAndRotation, defaultFlyToRotation, ToCutDownScaleType, ToScaleType, ESPolygonFence, ESUeViewer } from "esobjs-xe2-plugin/dist-node/esobjs-xe2-plugin-main";
import { ESForest, ESJTree, newESJTreeParam } from ".";
import { ESSceneObject, ObjResettingWithEvent, SceneObjectPickedInfo } from 'xbsj-xe2/dist-node/xe2-base-objects';
import * as turf from '@turf/turf';
import { Destroyable } from "xbsj-renderer/dist-node/xr-base-utils";

export class UeESForest<T extends ESForest = ESForest> extends UeESVisualObject<T> {
    static readonly type = this.register<ESForest>(ESForest.type, this);

    static override combinationClass = true;

    private _eSSeparateFoliage = this.dv(new ESSeparateFoliage());
    get eSSeparateFoliage() { return this._eSSeparateFoliage; }

    constructor(sceneObject: T, ueViewer: UeViewer) {
        super(sceneObject, ueViewer);

        const viewer = ueViewer.viewer;
        if (!viewer) {
            console.warn(`UeESForest: viewer is undefined!`);
            return;
        }
        const eSSeparateFoliage = this.eSSeparateFoliage;
        eSSeparateFoliage.allowPicking = true;
        ueViewer.add(eSSeparateFoliage);
        this.dispose(() => ueViewer.delete(eSSeparateFoliage))
        {
            const update = () => {
                ueViewer.mountPakFiles(sceneObject.treeTypesUE.map(item => {
                    return {
                        name: item.name,
                        path: item.meshPath
                    }
                })).then((e: any) => {
                    if (e.error != '') {
                        console.log('挂载树种Pak资源失败，请检查');
                    }
                })
                eSSeparateFoliage.treeTypes = sceneObject.treeTypesUE.map(item => {
                    const ueTypeNumber = item.meshPath.split("\\").pop().split(".")[0] as string;
                    return {
                        ...item,
                        meshPath: `StaticMesh'/Game/HSKJ/Meshes/Trees/${ueTypeNumber.split("_")[0]}/${ueTypeNumber}/SM_Tree_${ueTypeNumber}.SM_Tree_${ueTypeNumber}'`
                    }
                });
            }
            // update();
            this.ad(sceneObject.treeTypesEvent.don(update))
        }
        {
            const update = (treeParams: newESJTreeParam[]) => {
                eSSeparateFoliage.addTrees(treeParams)
            }
            if (sceneObject.trees.length != 0) {
                const switchDate = sceneObject.formatData(sceneObject.trees, sceneObject.treeTypesAll);
                update(switchDate);
            }
            this.dispose(sceneObject.addEvent.disposableOn(update));
        }

        this.dispose(sceneObject.removeAllEvent.disposableOn(() => {
            eSSeparateFoliage.removeAllTrees()
        }));

        this.dispose(sceneObject.updateEvent.disposableOn((treeParams: newESJTreeParam[]) => {
            eSSeparateFoliage.updateTreeParams(treeParams)
        }));

        this.dispose(sceneObject.removeEvent.disposableOn((treeIds: string[]) => {
            sceneObject.cutDown(treeIds, 0);
        }))
        this.dispose(sceneObject.cutDownEvent.disposableOn((treeIds, timeLength) => {
            const toCutDownScaleTypes = treeIds.map(item => {
                const treeParam = sceneObject.treesParam.find(it => item === it.id);
                if (!treeParam) return undefined;
                return {
                    [item]: [[0.00001, 0.00001, 0.00001], treeParam.treeTypeId]
                } as ToCutDownScaleType;
            }).filter(item => item != undefined);
            eSSeparateFoliage.cutDownTrees(toCutDownScaleTypes, timeLength)
        }));
        this.dispose(sceneObject.growthEvent.disposableOn((treeParams: newESJTreeParam[], timeLength: number) => {
            const toScaleType = treeParams.map(item => {
                const treeParam = sceneObject.treesParam.find(it => it.id == item.id);
                if (!treeParam) return undefined;
                return {
                    [item.id]: [treeParam.scale, treeParam.scale, item.scale, item.treeTypeId]
                } as ToScaleType;
            }).filter(item => item != undefined);
            eSSeparateFoliage.growthSimulation(toScaleType, timeLength, timeLength);
        }));
        this.ad(new ObjResettingWithEvent(sceneObject.highlightTreeEvent, (treeId: string | string[]) => {
            return new highLight(ueViewer, sceneObject, treeId);
        }))
        this.dispose(this.eSSeparateFoliage.pickedEvent.don(pickedInfo => {
            if (sceneObject.allowPicking ?? false) {
                //@ts-ignore
                if (pickedInfo.childPickedInfo && pickedInfo.childPickedInfo.uePickResult) {
                    eSSeparateFoliage.getIdByComponentNameAndHitItem(
                        ueViewer,
                        //@ts-ignore
                        pickedInfo.childPickedInfo.uePickResult.componentName,
                        //@ts-ignore
                        pickedInfo.childPickedInfo.uePickResult.hitItem
                    ).then((res: any) => {
                        if (res.error == "" && res.re && res.re.TreeId) {
                            //@ts-ignore
                            pickedInfo.childPickedInfo.uePickResult.treeId = res.re.TreeId;
                            sceneObject.pickedEvent.emit(new SceneObjectPickedInfo(sceneObject, pickedInfo));
                        }
                    });
                }
            }
        }))
        this.ad(sceneObject.flyToTreeEvent.don((treeId: string,) => {
            const tree = sceneObject.trees.find(tree => tree.id === treeId) as ESJTree;
            const position = tree.position;
            const rotation = [...defaultFlyToRotation] as [number, number, number];
            const { position: flyPosition, rotation: flyRotation } = getFlyToCenterAndRotation(position, rotation, 100);
            ueViewer.flyTo({
                "distance": 0,
                "heading": flyRotation[0],
                "pitch": flyRotation[1],
                "flyDuration": 1,
                "hDelta": 0,
                "pDelta": 0
            }, flyPosition)
        }))
        this.ad(sceneObject.flyToEvent.don((duration, id) => {
            eSSeparateFoliage.flyTo(duration);
        }))
    }
}
class highLight extends Destroyable {
    constructor(viewer: UeViewer, sceneObject: ESForest, treeId: string | string[]) {
        super();
        const treeIdArr = Array.isArray(treeId) ? treeId : [treeId];
        // 查找对应数据
        const trees = sceneObject.trees.filter(item => treeIdArr.includes(item.id));
        trees.forEach(item => {
            const eSPolygonFence = this.ad(new ESPolygonFence());
            eSPolygonFence.materialMode = 'gradientColor';
            eSPolygonFence.fillColor = [0, 255, 0, 0.2];
            viewer.add(eSPolygonFence);
            this.ad(() => viewer.delete(eSPolygonFence));
            const radius = Array.isArray(item.guanfu) ? Math.max(...item.guanfu) : item.guanfu;;
            const options = { steps: 18, units: 'meters' };
            //@ts-ignore
            const circle = turf.circle(item.position, radius, options);
            eSPolygonFence.points = circle.geometry.coordinates[0].map(it => { return [it[0], it[1], item.position[2]] });
            eSPolygonFence.height = item.shugao;
        })
    }
}